﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.IO;
using System.Text.RegularExpressions;
using Obra.SmugMug.Api;
using System.Collections.ObjectModel;

namespace Obra.PowerShell.SmugMug
{
    [CmdletProvider("SmugMug", ProviderCapabilities.Credentials)]
    public class CmdletProvider :
        NavigationCmdletProvider
    {
        //private static PSTraceSource tracer = new PSTraceSource();

        private DriveInfo DriveInfo
        {
            get { return (DriveInfo)this.PSDriveInfo; }
        }

        internal IPathMappingService PathMappingService
        {
            get { return this.DriveInfo.PathMappingService; }
        }

        #region DriveCmdletProvider

        /// <summary>
        /// News the drive.
        /// </summary>
        /// <param name="drive">The drive.</param>
        /// <returns></returns>
        protected override PSDriveInfo NewDrive(PSDriveInfo drive)
        {
            if (drive == null)
            {
                this.WriteError(new ErrorRecord(
                    new ArgumentException("drive"),
                    "NullDrive",
                    ErrorCategory.InvalidArgument,
                    null));

                return null;
            }

            if (0 != String.Compare(Resource.Root, drive.Root, true/*ignoreCase*/))
            {
                this.WriteError(new ErrorRecord(
                    new ArgumentException("root"),
                    "InvalidRoot",
                    ErrorCategory.InvalidArgument,
                    null));

                return null;
            }

            DriveInfo driveInfo = new DriveInfo(
                drive,
                (DynamicParameters)this.DynamicParameters);

            driveInfo.PathMappingService = new PathMappingServiceProvider(
                driveInfo.Root,
                this,
                driveInfo.SmugMugClient);

            this.WriteDebug("Connecting to SmugMug...");
            this.WriteDebug(String.Format("NewDrive:: root={0}", driveInfo.Root));

            driveInfo.SmugMugClient.LogOn();
            return driveInfo;
        }

        /// <summary>
        /// News the drive dynamic parameters.
        /// </summary>
        protected override object NewDriveDynamicParameters()
        {
            return new DynamicParameters();
        }

        /// <summary>
        /// Removes the drive.
        /// </summary>
        /// <param name="drive">The drive.</param>
        protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
        {
            if (drive == null)
            {
                this.WriteError(new ErrorRecord(
                    new ArgumentException("drive"),
                    "NullDrive",
                    ErrorCategory.InvalidArgument,
                    null));

                return null;
            }

            ((DriveInfo)drive).SmugMugClient.LogOff();
            return drive;
        }

        #endregion DriveCmdletProvider

        #region Item Methods

        /// <summary>
        /// Clears the item.
        /// </summary>
        /// <param name="path">The path.</param>
        protected override void ClearItem(string path)
        {
            throw new NotImplementedException();
            //ICmdletService service = this.PathMappingService.ToCmdletService(path);
            
            //service.Options = (DynamicParametersItem)this.DynamicParameters;
            //service.Clear();
        }

        /// <summary>
        /// Clears the item dynamic parameters.
        /// </summary>
        protected override object ClearItemDynamicParameters(string path)
        {
            return new DynamicParametersItem();
        }

        /// <summary>
        /// Gets the item.
        /// </summary>
        /// <param name="path">The path.</param>
        protected override void GetItem(string path)
        {
            ICmdletService cmdletService = this.PathMappingService.ToCmdletService(
                path);

            cmdletService.Options = (DynamicParametersItem)this.DynamicParameters;

            this.WriteItemObject(
                cmdletService.Get(),
                cmdletService.Path,
                cmdletService.IsContainer());
        }

        /// <summary>
        /// Gets the item dynamic parameters.
        /// </summary>
        protected override object GetItemDynamicParameters(string path)
        {
            return new DynamicParametersItem();
        }

        /// <summary>
        /// Invokes the default action.
        /// </summary>
        protected override void InvokeDefaultAction(string path)
        {
            ICmdletService service = this.PathMappingService.ToCmdletService(path);
            
            service.Options = (DynamicParametersItem)this.DynamicParameters;

            System.Diagnostics.Process.Start(
                service.GetUri().ToString());
        }

        /// <summary>
        /// Invokes the default action dynamic parameters.
        /// </summary>
        protected override object InvokeDefaultActionDynamicParameters(string path)
        {
            return new DynamicParametersItem();
        }

        /// <summary>
        /// Items the exists.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        protected override bool ItemExists(string path)
        {
            try
            {
                ICmdletService service = this.PathMappingService.ToCmdletService(path);
                service.Options = (DynamicParametersItem)this.DynamicParameters;

                return service.Exists();
            }
            catch (ArgumentException)
            {
                return false;
            }
        }

        /// <summary>
        /// Items the exists dynamic parameters.
        /// </summary>
        protected override object ItemExistsDynamicParameters(string path)
        {
            return new DynamicParametersItem();
        }

        /// <summary>
        /// Sets the item.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="value">The value.</param>
        protected override void SetItem(string path, object value)
        {
            throw new NotImplementedException("SetItem");
        }

        /// <summary>
        /// Determines whether [is valid path] [the specified path].
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>
        /// 	<c>true</c> if [is valid path] [the specified path]; otherwise, <c>false</c>.
        /// </returns>
        protected override bool IsValidPath(string path)
        {
            return Path.IsValidPath(path);
        }

        #endregion Item Methods

        #region Container Methods

        /// <summary>
        /// Copies the item.
        /// </summary>
        protected override void CopyItem(string path, string copyPath, bool recurse)
        {
            throw new NotImplementedException("CopyItem");
        }

        /// <summary>
        /// Gets the child items.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="recurse">if set to <c>true</c> [recurse].</param>
        protected override void GetChildItems(string path, bool recurse)
        {
            ICmdletService service = this.PathMappingService.ToCmdletService(
                path);

            service.Options = (DynamicParametersItem)this.DynamicParameters;

            service.GetChildren().ToList().ForEach(
                x => this.WriteItemObject(x.Child, x.Path, x.IsContainer));
        }

        /// <summary>
        /// Gets the child items dynamic parameters.
        /// </summary>
        protected override object GetChildItemsDynamicParameters(string path, bool recurse)
        {
            return new DynamicParametersItem();
        }

        /// <summary>
        /// Gets the child names.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="returnContainers">The return containers.</param>
        protected override void GetChildNames(string path, ReturnContainers returnContainers)
        {
            ICmdletService service = this.PathMappingService.ToCmdletService(
                path);

            service.Options = (DynamicParametersItem)this.DynamicParameters;
            
            service.GetChildren().ToList().ForEach(
                x => this.WriteItemObject(x.Name, x.Path, x.IsContainer));
        }

        /// <summary>
        /// Gets the child names dynamic parameters.
        /// </summary>
        protected override object GetChildNamesDynamicParameters(string path)
        {
            return new DynamicParametersItem();
        }

        /// <summary>
        /// Determines whether [has child items] [the specified path].
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>
        /// 	<c>true</c> if [has child items] [the specified path]; otherwise, <c>false</c>.
        /// </returns>
        protected override bool HasChildItems(string path)
        {
            return this.IsItemContainer(path);
        }

        protected override void MoveItem(string path, string destination)
        {
            ICmdletService service = this.PathMappingService.ToCmdletService(
                path);

            service.Options = (DynamicParametersItem)this.DynamicParameters;
            service.Move(destination);
        }

        /// <summary>
        /// Moves the item dynamic parameters.
        /// </summary>
        protected override object MoveItemDynamicParameters(string path, string destination)
        {
            return new DynamicParametersItem();
        }

        protected override void NewItem(string path, string itemTypeName, object newItemValue)
        {
            ICmdletService service = this.PathMappingService.ToCmdletService(
                path);

            service.Options = (DynamicParametersItem)this.DynamicParameters;
            service.New(itemTypeName, newItemValue);
        }

        /// <summary>
        /// News the item dynamic parameters.
        /// </summary>
        protected override object NewItemDynamicParameters(string path, string itemTypeName, object newItemValue)
        {
            return new DynamicParametersItem();
        }

        protected override void RemoveItem(string path, bool recurse)
        {
            ICmdletService service = this.PathMappingService.ToCmdletService(
                path);
            
            service.Options = (DynamicParametersItem)this.DynamicParameters;
            service.Remove();
        }

        /// <summary>
        /// Removes the item dynamic parameters.
        /// </summary>
        protected override object RemoveItemDynamicParameters(string path, bool recurse)
        {
            return new DynamicParametersItem();
        }

        /// <summary>
        /// Renames the item.
        /// </summary>
        protected override void RenameItem(string path, string newName)
        {
            ICmdletService service = this.PathMappingService.ToCmdletService(
                path);
            
            service.Options = (DynamicParametersItem)this.DynamicParameters;
            service.Rename(newName);
        }

        /// <summary>
        /// Renames the item dynamic parameters.
        /// </summary>
        protected override object RenameItemDynamicParameters(string path, string newName)
        {
            return new DynamicParametersItem();
        }

        #endregion Container Methods

        #region Navigation

        /// <summary>
        /// Gets the name of the child.
        /// </summary>
        /// <param name="path">The path to get child of.</param>
        /// <remarks>
        /// <para>
        /// It is unclear to me why, but if I use the default implementation of
        /// this method the CLI is not very responsive.  The base method takes 
        /// approximately 1-2 second to complete, and yet it doesn't really
        /// do anything that should consume that much time.
        /// </para>
        /// </remarks>
        protected override string GetChildName(string path)
        {
            return Path.GetChildName(path);
        }

        /// <summary>
        /// Determines whether [is item container] [the specified path].
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>
        /// 	<c>true</c> if [is item container] [the specified path]; otherwise, <c>false</c>.
        /// </returns>
        protected override bool IsItemContainer(string path)
        {
            try
            {
                ICmdletService service = this.PathMappingService.ToCmdletService(
                    path);

                service.Options = (DynamicParametersItem)this.DynamicParameters;

                return service.IsContainer();
            }
            catch (Exception)
            {
                return false;
            }
        }

        #endregion Navigation
    }
}
